package com.future.spring.annotation;

import com.future.spring.exception.BeanCreationException;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * @author weber
 * @Description:
 * @Date 2025/7/31 10:21
 */
public class BeanDefinition implements Comparable<BeanDefinition> {

    private String name;
    private int order;
    private Class<?> beanClass;
    private Constructor<?> constructor;
    private boolean primary;
    private String initMethodName;
    private String initMethod;
    private String destroyMethodName;
    private Method destroyMethod;
    private String factoryName;
    private Method factoryMethod;

    private Object instance;

    public BeanDefinition(String name,
                          Class<?> beanClazz,
                          Constructor<?> constructor,
                          int order,
                          boolean primary,
                          String initMethodName,
                          String destroyMethodName,
                          Method initMethod,
                          Method destroyMethod) {
        this.name = name;
        this.beanClass = beanClazz;
        this.factoryName = null;
        this.factoryMethod = null;
        this.constructor = constructor;
        this.order = order;
        this.primary = primary;
        this.constructor.setAccessible(true);
        setInitAndDestroyMethod(initMethodName, destroyMethodName, initMethod, destroyMethod);
    }

    public BeanDefinition(String name,
                          Class<?> beanClazz,
                          String factoryName,
                          Method factoryMethod,
                          int order,
                          boolean primary,
                          String initMethodName,
                          String destroyMethodName,
                          Method initMethod,
                          Method destroyMethod) {
        this.name = name;
        this.beanClass = beanClazz;
        this.constructor = null;
        this.factoryName = factoryName;
        this.factoryMethod = factoryMethod;
        this.order = order;
        this.primary = primary;
        constructor.setAccessible(true);
        setInitAndDestroyMethod(initMethodName, destroyMethodName, initMethod, destroyMethod);
    }

    private void setInitAndDestroyMethod(String initMethodName, String destroyMethodName, Method initMethod, Method destroyMethod) {
        this.initMethodName = initMethodName;
        this.destroyMethodName = destroyMethodName;
        if (initMethod != null) {
            initMethod.setAccessible(true);
        }
        if (destroyMethod != null) {
            destroyMethod.setAccessible(true);
        }
        this.initMethod = initMethodName;
        this.destroyMethod = destroyMethod;
    }

    @Override
    public int compareTo(BeanDefinition o) {
        int cmp = Integer.compare(this.order, o.order);
        if (cmp != 0) {
            return cmp;
        }
        return this.name.compareTo(o.name);
    }

    public String getName() {
        return name;
    }

    public int getOrder() {
        return order;
    }

    public Class<?> getBeanClass() {
        return beanClass;
    }

    public Constructor<?> getConstructor() {
        return constructor;
    }

    public boolean isPrimary() {
        return primary;
    }

    public String getInitMethodName() {
        return initMethodName;
    }

    public String getInitMethod() {
        return initMethod;
    }

    public String getDestroyMethodName() {
        return destroyMethodName;
    }

    public Method getDestroyMethod() {
        return destroyMethod;
    }

    public String getFactoryName() {
        return factoryName;
    }

    public Method getFactoryMethod() {
        return factoryMethod;
    }

    public Object getInstance() {
        return instance;
    }

    public void setInstance(Object instance) {
        this.instance = instance;
    }

    public Object getRequiredInstance() {
        if (instance == null) {
            throw new BeanCreationException(String.format("Bean '%s' has not been created", name));
        }
        return this.instance;
    }
}
